home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 22 / AACD 22.iso / AACD / Online / Apache / lib / php / DB / pgsql.php < prev    next >
Encoding:
PHP Script  |  2001-03-06  |  11.9 KB  |  463 lines

  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP version 4.0                                                      |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997, 1998, 1999, 2000 The PHP Group                   |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Rui Hirokawa <louis@cityfujisawa.ne.jp>                     |
  17. // |                                                                      |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // Database independent query interface definition for PHP's PostgreSQL
  21. // extension.
  22. //
  23. // [SSB] Problems in this code:
  24. //
  25. // 1. $this->row is used as a row counter
  26. // for the fetchRow() implementation.  There are two problems with this:
  27. // First of all, $this->row is not reset when the result is freed.  Also,
  28. // If the user creates two DB_result objects on the same DB connection,
  29. // it will break completely because both result sets will be using the
  30. // same row counter.  Solution: change $this->row into an array indexed
  31. // by resource id.
  32. // --> $this->row is changed to an indexed array. (R.Hirokawa)
  33. //
  34. // 2. The pgsql extension currently does not have error codes.  This
  35. // should be fixed so DB_pgsql can do portable error codes.
  36. // --> The error codes are not supported in the current pgsql API (libpq).
  37. //
  38. // 3. The transaction is supported by PostgreSQL, 
  39. //    but the current implementation is not useful to use the transaction.
  40.  
  41.  
  42. //
  43. // XXX legend:
  44. //
  45. // XXX ERRORMSG: The error message from the pgsql function should
  46. //                 be registered here.
  47. //
  48.  
  49. require_once 'DB/common.php';
  50.  
  51. class DB_pgsql extends DB_common {
  52.     // {{{ properties
  53.  
  54.     var $connection;
  55.     var $phptype, $dbsyntax;
  56.     var $prepare_tokens = array();
  57.     var $prepare_types = array();
  58.     var $numrows;
  59.     var $row;
  60.  
  61.     // }}}
  62.  
  63.     // {{{ constructor
  64.  
  65.     function DB_pgsql() {
  66.         $this->phptype = 'pgsql';
  67.         $this->dbsyntax = 'pgsql';
  68.         $this->features = array(
  69.             'prepare' => false,
  70.             'pconnect' => true,
  71.             'transactions' => true
  72.         );
  73.         $this->errorcode_map = array();
  74.         $this->numrows = array();
  75.         $this->row = array();
  76.     }
  77.  
  78.     // }}}
  79.  
  80.     // {{{ connect()
  81.  
  82.     /**
  83.      * Connect to a database and log in as the specified user.
  84.      *
  85.      * @param $dsn the data source name (see DB::parseDSN for syntax)
  86.      * @param $persistent (optional) whether the connection should
  87.      *        be persistent
  88.      *
  89.      * @return int DB_OK on success, a DB error code on failure
  90.      */
  91.     function connect(&$dsn, $persistent = false) {
  92.         if (is_array($dsn)) {
  93.             $dsninfo = &$dsn;
  94.         } else {
  95.             $dsninfo = DB::parseDSN($dsn);
  96.         }
  97.         if (!$dsninfo || !$dsninfo['phptype']) {
  98.             return $this->raiseError(); // XXX ERRORMSG
  99.         }
  100.         $dbhost = $dsninfo['hostspec'] ? $dsninfo['hostspec'] : 'localhost';
  101.         $protocol = $dsninfo['protocol'] ? $dsninfo['protocol'] : 'tcp';
  102.         $user = $dsninfo['username'];
  103.         $pw = $dsninfo['password'];
  104.         $dbname = $dsninfo['database'];
  105.         $options = $dsninfo['options'];
  106.         $tty = $dsninfo['tty'];
  107.         $port = $dsninfo['port'] ? $dsninfo['port'] : '5432';
  108.  
  109.         $connect_function = $persistent ? 'pg_pconnect' : 'pg_connect';
  110.  
  111.         if (($protocol == 'unix') && $dbname) {
  112.             $connect_params = "dbname=$dbname";
  113.             if ($user) {
  114.                 $connect_params .= " user=$user";
  115.             }
  116.             if ($pw) {
  117.                 $connect_params .= " password=$pw";
  118.             }
  119.             $conn = $connect_function($connect_params);
  120.         } elseif ($dbhost && $user && $pw && $dbname) {
  121.             $conn = $connect_function(
  122.                 "host=$dbhost port=$port dbname=$dbname user=$user password=$pw");
  123.         } elseif ($dbhost && $dbname && $options && $tty) {
  124.             $conn = $connect_function($dbhost, $port, $options, $tty, $dbname);
  125.         } elseif ($dbhost && $dbname) {
  126.             $conn = $connect_function($dbhost, $port, $dbname);
  127.         } else {
  128.             $conn = false;
  129.         }
  130.         if ($conn == false) {
  131.             return $this->raiseError(); // XXX ERRORMSG
  132.         }
  133.         $this->connection = $conn;
  134.         return DB_OK;
  135.     }
  136.  
  137.     // }}}
  138.     // {{{ disconnect()
  139.  
  140.     /**
  141.      * Log out and disconnect from the database.
  142.      *
  143.      * @return bool TRUE on success, FALSE if not connected.
  144.      */
  145.     function disconnect() {
  146.         return pg_close($this->connection); // XXX ERRORMSG
  147.     }
  148.  
  149.     // }}}
  150.     // {{{ query()
  151.  
  152.  
  153.     /**
  154.      * Send a query to PostgreSQL and return the results as a DB_result object.
  155.      *
  156.      * @param $query the SQL query
  157.      *
  158.      * @return object a DB_result object on success, a DB error code
  159.      * on failure
  160.      */
  161.     function &query($query) {
  162.         $this->last_query = $query;
  163.         $result = pg_exec($this->connection, $query);
  164.         if (!$result) {
  165.             return pg_errormessage($this->connection);
  166.         }
  167.         // Determine which queries that should return data, and which
  168.         // should return an error code only.
  169.         if (preg_match('/(SELECT|SHOW)/i', $query)) {
  170.             $resultObj = new DB_result($this, $result);
  171.             $this->row[$result] = 0; // reset the row counter. 
  172.             $this->numrows[$result] = pg_numrows($result); 
  173.             return $resultObj;
  174.         } else {
  175.             return DB_OK;
  176.         }
  177.     }
  178.  
  179.     // }}}
  180.     // {{{ simpleQuery()
  181.  
  182.     /**
  183.      * Send a query to PostgreSQL and return the results as a PostgreSQL resource
  184.      * identifier.
  185.      *
  186.      * @param $query the SQL query
  187.      *
  188.      * @return int returns a valid PostgreSQL result for successful SELECT
  189.      * queries, DB_OK for other successful queries.  A DB error code
  190.      * is returned on failure.
  191.      */
  192.     function simpleQuery($query) {
  193.         $this->last_query = $query;
  194.         $result = pg_exec($this->connection, $query);
  195.         if (!$result) {
  196.             return pg_errormessage($this->connection);
  197.         }
  198.         // Determine which queries that should return data, and which
  199.         // should return an error code only.
  200.         if (preg_match('/(SELECT|SHOW)/i', $query)) {
  201.             $this->row[$result] = 0; // reset the row counter.
  202.             $this->numrows[$result] = pg_numrows($result);  
  203.             return $result;
  204.         } else {
  205.             return DB_OK;
  206.         }
  207.     }
  208.  
  209.     // }}}
  210.     // {{{ fetchRow()
  211.  
  212.     /**
  213.      * Fetch a row and return as array.
  214.      *
  215.      * @param $result PostgreSQL result identifier
  216.      * @param $fetchmode how the resulting array should be indexed
  217.      *
  218.      * @return int an array on success, a DB error code on failure, NULL
  219.      *             if there is no more data
  220.      */
  221.     function &fetchRow($result, $fetchmode = DB_FETCHMODE_DEFAULT) {
  222.         if ($fetchmode == DB_FETCHMODE_DEFAULT) {
  223.             $fetchmode = $this->fetchmode;
  224.         }
  225.         if ($this->row[$result]>=$this->numrows[$result]){
  226.             return NULL;
  227.         }
  228.         if ($fetchmode & DB_FETCHMODE_ASSOC) {
  229.             $row = pg_fetch_array($result, $this->row[$result]);
  230.         } else {
  231.             $row = pg_fetch_row($result, $this->row[$result]);
  232.         }
  233.         if (!$row) {
  234.             $err = pg_errormessage($this->connection);
  235.             if (!$err) {
  236.                 return NULL;
  237.             }
  238.             return $err;
  239.         }
  240.         $this->row[$result]++;
  241.         return $row;
  242.     }
  243.  
  244.     // }}}
  245.     // {{{ fetchInto()
  246.  
  247.     /**
  248.      * Fetch a row and insert the data into an existing array.
  249.      *
  250.      * @param $result PostgreSQL result identifier
  251.      * @param $arr (reference) array where data from the row is stored
  252.      * @param $fetchmode how the array data should be indexed
  253.      *
  254.      * @return int DB_OK on success, a DB error code on failure
  255.      */
  256.     function fetchInto($result, &$arr, $fetchmode = DB_FETCHMODE_DEFAULT) {
  257.         if ($fetchmode == DB_FETCHMODE_DEFAULT) {
  258.             $fetchmode = $this->fetchmode;
  259.         }
  260.         if ($this->row[$result]>=$this->numrows[$result]){
  261.             return NULL;
  262.         }
  263.         if ($fetchmode & DB_FETCHMODE_ASSOC) {
  264.             $arr = pg_fetch_array($result, $this->row[$result]);
  265.         } else {
  266.             $arr = pg_fetch_row($result, $this->row[$result]);
  267.         }
  268.         if (!$arr) {
  269.             /* 
  270.              $errno = pg_errormessage($this->connection);
  271.              if (!$errno) {
  272.                 return NULL;
  273.              }
  274.              return $errno;
  275.             */
  276.             // the error codes are not supported in pgsql. 
  277.             return $this->raiseError(DB_ERROR_NOT_CAPABLE); 
  278.         }
  279.         $this->row[$result]++;
  280.         return DB_OK;
  281.     }
  282.  
  283.     // }}}
  284.     // {{{ freeResult()
  285.  
  286.     /**
  287.      * Free the internal resources associated with $result.
  288.      *
  289.      * @param $result PostgreSQL result identifier or DB statement identifier
  290.      *
  291.      * @return bool TRUE on success, FALSE if $result is invalid
  292.      */
  293.     function freeResult($result) {
  294.         if (is_resource($result)) {
  295.             return pg_freeresult($result);
  296.         }
  297.         if (!isset($this->prepare_tokens[$result])) {
  298.             return false;
  299.         }
  300.         unset($this->prepare_tokens[$result]);
  301.         unset($this->prepare_types[$result]);
  302.         unset($this->row[$result]);
  303.         unset($this->numrows[$result]);
  304.         return true; 
  305.     }
  306.  
  307.     // }}}
  308.     // {{{ numCols()
  309.  
  310.     /**
  311.      * Get the number of columns in a result set.
  312.      *
  313.      * @param $result PostgreSQL result identifier
  314.      *
  315.      * @return int the number of columns per row in $result
  316.      */
  317.     function numCols($result) {
  318.         $cols = pg_numfields($result);
  319.         if (!$cols) {
  320.             return pg_errormessage($this->connection);
  321.         }
  322.         return $cols;
  323.     }
  324.  
  325.     // }}}
  326.     // {{{ numRows()
  327.  
  328.     /**
  329.      * Get the number of rows in a result set.
  330.      *
  331.      * @param $result PostgreSQL result identifier
  332.      *
  333.      * @return int the number of rows in $result
  334.      */
  335.     function numRows($result) {
  336.         $rows = pg_numrows($result);
  337.         if (!$rows) {
  338.             return pg_errormessage($this->connection);
  339.         }
  340.         return $rows;
  341.     }
  342.  
  343.     // }}}
  344.     // {{{ errorNative()
  345.  
  346.     /**
  347.      * Get the native error code of the last error (if any) that
  348.      * occured on the current connection.
  349.      *
  350.      * @return int native PostgreSQL error code
  351.      */
  352.     function errorNative() {
  353.     /*    return pg_errormessage($this->connection); */
  354.         // the error codes are not supported in pgsql. 
  355.         return $this->raiseError(); 
  356.     }
  357.  
  358.     // }}}
  359.     // {{{ prepare()
  360.  
  361.     /**
  362.      * Prepares a query for multiple execution with execute().  With
  363.      * PostgreSQL, this is emulated.
  364.      */
  365.     function prepare($query) {
  366.         $tokens = split('[\&\?]', $query);
  367.         $token = 0;
  368.         $types = array();
  369.         for ($i = 0; $i < strlen($query); $i++) {
  370.             switch ($query[$i]) {
  371.                 case '?':
  372.                     $types[$token++] = DB_PARAM_SCALAR;
  373.                     break;
  374.                 case '&':
  375.                     $types[$token++] = DB_PARAM_OPAQUE;
  376.                     break;
  377.             }
  378.         }
  379.         $this->prepare_tokens[] = &$tokens;
  380.         end($this->prepare_tokens);
  381.         $k = key($this->prepare_tokens);
  382.         $this->prepare_types[$k] = $types;
  383.         return $k;
  384.     }
  385.  
  386.     // }}}
  387.     // {{{ execute()
  388.  
  389.     /**
  390.      * @return int returns a PostgreSQL result resource for successful
  391.      * SELECT queries, DB_OK for other successful queries.  A DB error
  392.      * code is returned on failure.
  393.      */
  394.     function execute($stmt, $data = false) {
  395.         $realquery = $this->execute_emulate_query($stmt, $data);
  396.         $this->last_query = $realquery;
  397.         $result = pg_exec($this->connection, $realquery);
  398.         if (!$result) {
  399.             return pg_errormessage($this->connection);
  400.         }
  401.         if (preg_match('/(SELECT|SHOW)/i', $realquery)) {
  402.             $this->row[$result] = 0; // reset the row counter.
  403.             $this->numrows[$result] = pg_numrows($result);
  404.             return $result;
  405.         } else {
  406.             return DB_OK;
  407.         }
  408.     }
  409.  
  410.     // }}}
  411.     // {{{ autoCommit()
  412.  
  413.     /**
  414.      * Enable/disable automatic commits [not supported by PostgreSQL]
  415.      */
  416.     function autoCommit($onoff = false) {
  417.         return $this->raiseError(DB_ERROR_NOT_CAPABLE);
  418.     }
  419.  
  420.     // }}}
  421.     // {{{ commit()
  422.  
  423.     /**
  424.      * Commit transactions on the current connection
  425.      */
  426.     function commit() {
  427.         $result = pg_exec($this->connection, "end;");
  428.         if (!$result) {
  429.             return pg_errormessage($this->connection);
  430.         }
  431.         return DB_OK;
  432.     }
  433.  
  434.     // }}}
  435.     // {{{ rollback()
  436.  
  437.     /**
  438.      * Roll back all uncommitted transactions on the current connection.
  439.      */
  440.     function rollback() {
  441.         $result = pg_exec($this->connection, "abort;");
  442.         if (!$result) {
  443.             return pg_errormessage($this->connection);
  444.         }
  445.         return DB_OK;
  446.     }
  447.  
  448.     // }}}
  449.  
  450.     // TODO/wishlist:
  451.     // simpleFetch
  452.     // simpleGet
  453.     // affectedRows
  454.     // longReadlen
  455.     // binmode
  456. }
  457.  
  458. // Local variables:
  459. // tab-width: 4
  460. // c-basic-offset: 4
  461. // End:
  462. ?>
  463.